iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 21
1
Modern Web

循序漸進學習 Javascript 測試系列 第 21

Day 21 測試 React 元件:使用 React Testing Library 體驗 Test Driven Development (TDD) - 1

  • 分享至 

  • xImage
  •  

什麼是 Test Driven Development (TDD)?

中文意思是「測試驅動開發」,是一種「先寫測試再寫開發」的開發流程。

TDD 是一個 red-green-refactor 的 cycle,它的概念就是:先寫好測試,當然這時候的測試是 fail 的(紅燈),再基於測試,補上必要的程式碼,讓測試 pass(綠燈),之後可以重構程式碼,重複「測試亮紅燈,修復後再亮綠燈」的過程。

透過先寫測試,事先釐清元件應該具備那些功能、應該測試哪些功能,再回頭補上元件應該有的功能,這種開發方式,更能確保元件是經過思考與設計的。

用 TDD 實作表單開發

我們現在試著用 TDD 的方式來開發一個表單。

這個表單主要功能是發表文章,它接收標題 (title) 、內容 (content)、標籤 (tag),並且有一個按鈕可以點擊送出表單,並發出 HTTP  request。

我們會經歷以下步驟,一步一步先寫測試再寫程式,重複亮紅燈再亮綠燈的循環過程:

  • 步驟一:開發表單元件結構
  • 步驟二:開發 submit button 功能
  • 步驟三:表單 API Call

步驟一:開發表單元件結構

在測試檔中引入元件及 React Testing Library,並命名測試名稱 'renders a form with title, content, tags, and a submit button'

tests/post-editor.js

import React from 'react'
import {Editor} from '../post-editor'
import {render} from '@testing-libraray/react'

test('renders a form with title, content, tags, and a submit button', () => {
  <Editor />
})

使用 getBYLabelTextgetByText 測試元件是否 render 在畫面上:

tests/post-editor.js

test('renders a form with title, content, tags, and a submit button', () => {
  const {getBYLabelText, getByText} = render(<Editor />)
  getByLabelText(/title/i)
  getByLabelText(/content/i)
  getByLabelText(/tags/i)
  getByText(/submit/i)
})

這時候測試是 fail 的,因為我們根本還沒開始寫 <Editor /> 這個元件,我們只是先定義好要測試什麼:

  • 要有一個 label 文字是 title 的 form control
  • 要有一個 label 文字是 content 的 form control
  • 要有一個 label 文字是 tags 的 form control
  • 要有一個 文字是 submit 的 button

現在我們開始寫 <Editor /> , 一個一個補上測試內定義的條件,讓測試亮綠燈:

post-editor.js

import React from 'react'

function Editor() {
  return ( 
    <form>
      <label htmlFor="title-input">Title</label>
      <input id="title-input" />

      <label htmlFor="content-input">Content</label>
      <textarea id="content-input" />

      <label htmlFor="tags-input">Tags</label>
      <textarea id="tags-input" />

      <button type="submit">Submit</button>
    </form>
  )
}

export {Editor}

這樣測試就亮綠燈了,完成表單目前的結構開發。

步驟二:開發 submit button 功能

完成表單結構之後,接下來要加上 submit button 的功能:點擊 submit button 之後,submit button 要 disabled

首先,回到測試檔案,我們加上測試:

  • getByText(/submit/i) 取得回傳的 submit button
  • 使用 fireEvent.click() 觸發點擊事件
  • 使用 expect().toBeDisabled() 驗證 submit button 是否 disabled

tests/post-editor.js

import React from 'react'
import {render, fireEvent} from '@testing-library/react' // 引入 fireEvent
import {Editor} from '../post-editor'

test('renders a form with title, content, tags, and a submit button', () => {
  const {getByLabelText, getByText} = render(<Editor />)
  getByLabelText(/title/i)
  getByLabelText(/content/i)
  getByLabelText(/tags/i)
  const submitButton = getByText(/submit/i)

  fireEvent.click(submitButton) // 點擊

  expect(submitButton).toBeDisabled() // 驗證 disabled
})

更新完上面的測試,現在跑測試會是 fail 亮紅燈 ❌。

我們回到 post-editor.js 檔案,補上需要的功能:

  • 在 tag 加上 onSubmit 事件及它的 handler handleSubmit
  • handleSubmit function 裡面加上 e.preventDefault() 阻止預設的 submit 後換頁
  • 設置 isSaving 這個 state,並在 handleSubmit function 裡 setIsSaving(true)
  • tag 加上 disabled={isSaving} ,設置 disabled 屬性基於 isSaving 這個 state

post-editor.js

function Editor() {
	const [isSaving, setIsSaving] = React.useState(false)
  function handleSubmit(e) {
    e.preventDefault()
    setIsSaving(true)
  }
  return ( 
    <form onSubmit={handleSubmit}>
      ...
			<button type="submit" disabled={isSaving}>Submit</button>
  )
}

測試再度亮起綠燈 ✅


上一篇
Day 20 測試 React 元件:測試 Error Boundary 元件
下一篇
Day 22 測試 React 元件:使用 React Testing Library 體驗 Test Driven Development (TDD) - 2
系列文
循序漸進學習 Javascript 測試30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言